﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TiposComuns.Objectos;
using System.Collections;
using System.Data.SqlClient;

namespace Pesquisa
{
    /// <summary>
    /// Representation of a list of nodes, that this server knows,
    /// within a certain range of identifiers. Each k-bucket is limited, in size,
    /// by the constant K, from this class.
    /// </summary>
    public class KBucket : IEnumerable<Person>
    {
        #region Consts
        public const int K = 3;
        #endregion

        #region Attributes
        private List<Person> bucs;          //List of nodes
        private int order;
        private bool bit;


        /// <summary>
        /// Returns the depth of the k-bucket
        /// </summary>
        public int Order
        {
            get { return order; }
            set { order = value; }
        }

        public List<Person> Bucs
        {
            get { return bucs; }
        }

        /// <summary>
        /// Determines the value of the bit associated to this k-bucket
        /// </summary>
        public bool Bit
        {
            get { return bit; }
            set { bit = value; }
        }

        /// <summary>
        /// Determines if the host node is contained
        /// on the range of this k-bucket
        /// </summary>
        public bool IsCont
        {
            get;
            set;
        }
        #endregion

        #region Constructors
        public KBucket()
        {
            this.bucs = new List<Person>();
            this.order = TiposComuns.Objectos.HashService.NBITS;
            this.bit = false;
        }

        public KBucket(int order, bool bit)
        {
            this.bucs = new List<Person>();
            this.order = order;
            this.bit = bit;
        }
        #endregion

        #region Methods

        public int Count()
        {
            return bucs.Count;
        }

        /// <summary>
        /// Adds a new person to the k-bucket
        /// </summary>
        /// <param name="person">New person</param>
        /// <returns>Returns true if the k-bucket isn't full, false otherwise</returns>
        public bool Add(Person person)
        {
            if (this.bucs.Count < KBucket.K)
            {
                this.bucs.Add(person);
                
                return true;
            }
            else return false;
        }

        /// <summary>
        /// Remove a node from the k-bucket
        /// </summary>
        /// <param name="person">node</param>
        public void Remove(Person person)
        {
            this.bucs.Remove(person);
        }
 

        /// <summary>
        /// Order k-bucket by the last contact made
        /// </summary>
        public void OrderByDate()
        {
            
            this.bucs.OrderBy(p1 => p1.LastAccess);
        }

        /// <summary>
        /// Splits the k-bucket in two
        /// </summary>
        /// <returns>New k-bucket whose elements have and hash greater than 2^bit</returns>
        public KBucket Split()
        {
            this.order--;
            this.bit = false;
            
            KBucket buc = new KBucket(this.order, true);
                        
            for (int i = 0; i < this.bucs.Count; i++)
            {
                if (bucs[i].GetBit(this.order) == 1)
                {
                    buc.Add(bucs[i]);
                    bucs.RemoveAt(i);
                    i--;
                }
            }

            return buc;
        }
        #endregion

        #region IEnumerable<Person> Members

        IEnumerator<Person> IEnumerable<Person>.GetEnumerator()
        {
            return bucs.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return bucs.GetEnumerator();
        }

        #endregion
    }    
}
